from django.db import models
from django_tenants.utils import schema_context

from apps.core.utils import date_time as datetime_helper
from apps.core.models import GenericModel
from apps.booking.models import Booking, Appointment
from apps.tenant.models import ProviderServices
from apps.client.models import Client
from .types import (
    INVOICE_STATUS_CHOICES,
    CLIENT_INVOICE_STATUS_CHOICES,
    CLIENT_PAYMENT_TYPE_CHOICES,
    InvoiceStatus,
    ClientInvoiceStatus,
    ClientPaymentType
)
from apps.client.types import CLIENT_BILLING_TYPE, ClientBillingType
from ..location.models import ProviderBillings


# Incrementing number for provider invoices
def increment_invoice_number():
    dt = datetime_helper.now()
    year = f'{abs(dt.year) % 100}'
    month = f'{dt.month:02d}'
    day = f'{dt.day:02d}'

    today_range = datetime_helper.get_time_range()
    with schema_context("public"):
        invoices_count = ProviderBillings.objects.filter(
            created_at__range=today_range).count()
        invoices_count_formatted = '{:05}'.format(invoices_count + 1)
        invoice_no = '{}{}{}{}'.format(year, day, month, invoices_count_formatted)
        while ProviderBillings.objects.filter(invoice_number=invoice_no).exists():
            invoice_no = str(int(invoice_no) + 1)
        return invoice_no


# Incrementing number for client invoices
def increment_client_invoice_number():
    dt = datetime_helper.now()
    year = f'{abs(dt.year) % 100}'
    month = f'{dt.month:02d}'
    day = f'{dt.day:02d}'

    today_range = datetime_helper.get_time_range()
    client_invoices_count = ClientInvoice.objects.filter(
        created_at__range=today_range).count()
    client_invoices_count_formatted = '{:05}'.format(client_invoices_count + 1)
    client_invoice_no = '{}{}{}{}'.format(
        year, month, day, client_invoices_count_formatted)
    return client_invoice_no


def increment_super_bill_number():
    dt = datetime_helper.now()
    year = f'{abs(dt.year) % 100}'
    month = f'{dt.month:02d}'
    day = f'{dt.day:02d}'

    today_range = datetime_helper.get_time_range()
    client_invoices_count = SuperBill.objects.filter(
        created_at__range=today_range).count()
    client_invoices_count_formatted = '{:05}'.format(client_invoices_count + 1)
    client_invoice_no = '{}{}{}{}'.format(
        year, month, day, client_invoices_count_formatted)
    return client_invoice_no


# Invoice model
class Invoice(GenericModel):
    invoice_number = models.CharField(null=True,
                                      blank=True,
                                      max_length=11,
                                      unique=True,
                                      default=increment_invoice_number)
    due_date = models.DateTimeField()
    total_amount = models.DecimalField(max_digits=12, decimal_places=5)
    status = models.IntegerField(
        choices=INVOICE_STATUS_CHOICES,
        default=InvoiceStatus.UNPAID.value
    )
    bookings = models.ManyToManyField(Booking, related_name='invoices')
    payment_id = models.CharField(max_length=50, null=True, blank=True)
    applied_promo_credit = models.DecimalField(
        max_digits=10,
        decimal_places=2,
        default=0.0
    )
    applied_ethera_credit = models.DecimalField(
        max_digits=10,
        decimal_places=2,
        default=0.0
    )
    received_credit = models.DecimalField(
        max_digits=10,
        decimal_places=2,
        default=0.0
    )
    provider_open_credit = models.DecimalField(
        max_digits=10,
        decimal_places=2,
        default=0.0
    )

    class Meta:
        db_table = 'invoices'


# Client Invoice model
class ClientInvoice(GenericModel):
    invoice_number = models.CharField(
        null=True,
        blank=True,
        max_length=11,
        default=increment_client_invoice_number
    )
    appointment = models.ForeignKey(Appointment,
                                    on_delete=models.CASCADE,
                                    null=True,
                                    related_name='appointment_invoice')
    status = models.IntegerField(
        choices=CLIENT_INVOICE_STATUS_CHOICES,
        default=ClientInvoiceStatus.UNPAID.value
    )
    issue_date = models.DateTimeField(null=True)
    client = models.ForeignKey(Client, on_delete=models.CASCADE, null=True)
    billing_type = models.CharField(choices=CLIENT_BILLING_TYPE,
                                    default=ClientBillingType.SELF_PAY.value,
                                    max_length=3)
    fees = models.DecimalField(max_digits=1000, decimal_places=2, default=0)
    due_date = models.DateTimeField(null=True)

    class Meta:
        db_table = 'client_invoices'


# Services we provided to a client in an appointment
class InvoiceServices(GenericModel):
    invoice = models.ForeignKey(ClientInvoice, on_delete=models.CASCADE, related_name='invoice_services', null=True)
    date = models.DateTimeField(null=True)
    service = models.ForeignKey(ProviderServices, on_delete=models.CASCADE)
    client = models.ForeignKey(Client, on_delete=models.CASCADE, null=True,
                               related_name='client_invoice_service')
    fees = models.DecimalField(decimal_places=2, max_digits=10, default=0)

    class Meta:
        db_table = 'invoice_services'


# After Client creates a payment
class ClientPayment(GenericModel):
    invoice = models.ForeignKey(ClientInvoice,
                                on_delete=models.CASCADE,
                                related_name='client_payments')
    price = models.DecimalField(max_digits=10, decimal_places=2, null=True)
    status = models.IntegerField(
        choices=CLIENT_PAYMENT_TYPE_CHOICES,
        default=ClientPaymentType.CASH.value
    )
    date_received = models.DateTimeField(auto_now_add=True, null=True)

    class Meta:
        db_table = 'client_payments'


class AccountCredit(models.Model):
    invoice = models.OneToOneField(Invoice, on_delete=models.CASCADE)
    opening_credit_balance = models.DecimalField(
        max_digits=12,
        decimal_places=5)
    credit_applied = models.DecimalField(max_digits=10, decimal_places=2)
    credit_received = models.DecimalField(max_digits=10, decimal_places=2)
    closing_credit_balance = models.DecimalField(
        max_digits=10, decimal_places=2)

    class Meta:
        db_table = 'account_credit'


class SuperBill(GenericModel):
    bill_number = models.CharField(
        null=True,
        blank=True,
        max_length=11,
        default=increment_super_bill_number
    )
    client_invoices = models.ManyToManyField(ClientInvoice,
                                             related_name='super_bill')

    class Meta:
        db_table = 'super_bill'